package org.hzero.interfaces.common.aspect;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.hzero.interfaces.common.annoations.KnifeMethodLog;
import org.hzero.interfaces.common.entity.KnifeInterfaceLogRecord;
import org.hzero.interfaces.common.helper.KnifeInterfaceLogHelper;
import org.hzero.interfaces.common.helper.director.KnifeInterfaceLogDirector;
import org.hzero.interfaces.common.helper.impl.KnifeAopMethodLogHelperImpl;
import org.hzero.interfaces.common.utils.KnifeLogParamUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.validation.MessageCodesResolver;

import javax.servlet.ServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Map;

/**
 * 1 service方法日志监控,配合{@link KnifeMethodLog}实现;只能作用于方法上，不会记录请求的IP等信息
 * 2 需要注入这个切面，切点为{@link KnifeMethodLog}
 *
 * @author tianhao.luo@hand-china.com
 */
@Component
@Order(200)
public class KnifeMethodLogAdvice implements MethodInterceptor {
    private static final Logger LOGGER = LoggerFactory.getLogger(KnifeMethodLogAdvice.class);


    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        // 切点只能用于public类型的方法
        Method api = methodInvocation.getMethod();
        // 只能监控service层的方法
        Object invoke = null;
        // 此处获取的是service上的注解
        KnifeMethodLog knifeMethodLog = api.getAnnotation(KnifeMethodLog.class);
        if (knifeMethodLog != null && knifeMethodLog.value()) {
            // 需要克隆一份参数，避免因为方法内部对他做了修改导致的日志存储异常
            Object[] arguments = methodInvocation.getArguments();
            Map<String,Object> map = KnifeLogParamUtil.deepCloneArgs(arguments,
                    api.getParameters(),
                    ServletRequest.class,
                    BindingResult.class,
                    MessageCodesResolver.class);
            // 请求内容
            KnifeInterfaceLogRecord knifeInterfaceLogRecord = new KnifeInterfaceLogRecord(new Date(),knifeMethodLog.interfaceLogDirection(), knifeMethodLog.interfaceEnum());
            KnifeInterfaceLogHelper aopKnifeInterfaceLogHelper;
            try {
                invoke = methodInvocation.proceed();
                aopKnifeInterfaceLogHelper = new KnifeAopMethodLogHelperImpl(knifeInterfaceLogRecord, HttpStatus.OK);
                KnifeInterfaceLogDirector knifeInterfaceLogDirector = new KnifeInterfaceLogDirector(aopKnifeInterfaceLogHelper);
                knifeInterfaceLogDirector.createHitfInterfaceLog(map, invoke, api);
            } catch (Throwable throwable) {
                // 记录错误日志
                aopKnifeInterfaceLogHelper = new KnifeAopMethodLogHelperImpl(knifeInterfaceLogRecord, HttpStatus.INTERNAL_SERVER_ERROR, new Exception(throwable));
                KnifeInterfaceLogDirector knifeInterfaceLogDirector = new KnifeInterfaceLogDirector(aopKnifeInterfaceLogHelper);
                knifeInterfaceLogDirector.createHitfInterfaceLog(map, invoke, api);
                throw throwable;
            }
        } else {
            invoke = methodInvocation.proceed();
        }
        return invoke;
    }
}
